package Verifier.ArithmeticSystem;

import java.math.BigInteger;
import Verifier.ByteTree.ByteTree;

public class ArithmeticConvertorFieldTester {
	
	static Field f = null;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			f = new Field(BigInteger.valueOf(263));
		} catch (Exception e1) {
			e1.printStackTrace();
			return;
		}
		System.out.println();
		try {
			if (!testFieldElement(new FieldElement(BigInteger.valueOf(258), f), "01000000020102"))
			{ return; }
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return;
		}
		System.out.println();
		
		ProductFieldElement prouctFieldResult = new ProductFieldElement();
		try {
			prouctFieldResult.addFieldElement(new FieldElement(BigInteger.valueOf(258), f));
			prouctFieldResult.addFieldElement(new FieldElement(BigInteger.valueOf(45), f));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return;
		}
		if (!testFieldProduct(prouctFieldResult, "0000000002010000000201020100000002002D"))
		{ return; }
		System.out.println();
		
		FieldElement[] fElements = new FieldElement[3];
		try {
			fElements[0] = new FieldElement(BigInteger.valueOf(1), f);
			fElements[1] = new FieldElement(BigInteger.valueOf(2), f);
			fElements[2] = new FieldElement(BigInteger.valueOf(3), f);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return;
		}
		
		if (!testFieldArray(fElements, "0000000003010000000200010100000002000201000000020003"))
		{ return; }
		System.out.println();
		
		ProductFieldElement[] pProuctFieldElements = new ProductFieldElement[3];
		try {
			pProuctFieldElements[0] = new ProductFieldElement();
			pProuctFieldElements[0].addFieldElement(new FieldElement(BigInteger.valueOf(1), f));
			pProuctFieldElements[0].addFieldElement(new FieldElement(BigInteger.valueOf(4), f));
			pProuctFieldElements[1] = new ProductFieldElement();
			pProuctFieldElements[1].addFieldElement(new FieldElement(BigInteger.valueOf(2), f));
			pProuctFieldElements[1].addFieldElement(new FieldElement(BigInteger.valueOf(5), f));
			pProuctFieldElements[2] = new ProductFieldElement();
			pProuctFieldElements[2].addFieldElement(new FieldElement(BigInteger.valueOf(3), f));
			pProuctFieldElements[2].addFieldElement(new FieldElement(BigInteger.valueOf(6), f));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return;
		}
		
		if (!testFieldProductArray(pProuctFieldElements, "000000000200000000030100000002000101000000020002010000000200030000000003010000000200040100000002000501000000020006"))
		{ return; }
	}
	
	private static boolean testFieldElement(FieldElement resultElement, String treeString) {
		System.out.println("Test : Field Element");
		System.out.println("----------------------------");
		// convert the byte tree into a Field
		System.out.println("Create Field Element : e = " + resultElement.getElement());
		FieldElement e = null;
		try {
			e = ArithmeticConvertor.ToFieldElement(new ByteTree(treeString), f);
			if (!e.equals(resultElement)) {
				System.out.println("Failed : the Field element created is different from the result");
				return (false);
			}
			System.out.println("OK : Field Element created");
		} catch (Exception ex) {
			System.out.println("Failed : creating the Field element");
			return (false);
		}
		
		System.out.println("The Field Element created is: " + e.getElement());
		
		// convert the Field into a byte tree
		System.out.println("Converting the Field element backwards:");
		try {
			ByteTree b = ArithmeticConvertor.ToByteTree(e);
			
			if (0 == b.getByteString().compareToIgnoreCase(treeString)) {
				System.out.println("OK : The created byte tree is the same as the one that created the element");
			} else {
				System.out.println("Failed : The created byte tree is the different as the one that created the element");
				System.out.println(b.getByteString());
				System.out.println(treeString);
			}
		} catch (Exception ex) {
			System.out.println("Failed to create the byte tree");
			return (false);
		}
		
		return (true);
	}
	
	private static void printProductFieldElement(ProductFieldElement groupProduct) {
		System.out.print("(");
		for (int i = 0 ; i < groupProduct.getNumberOfElements(); i++) {
			Element element = groupProduct.getElement(i);
			if (element instanceof FieldElement) {
				System.out.print(((FieldElement)element).getElement());
			} else {
				printProductFieldElement((ProductFieldElement)element);
			}
			if (i + 1 < groupProduct.getNumberOfElements()) {
				System.out.print(",");
			}
		}
		System.out.print(")");
	}
	
	private static boolean testFieldProduct(ProductFieldElement resultElement, String treeString) {
		System.out.println("Test : Product Field Element");
		System.out.println("----------------------------");
		// convert the byte tree into a Field
		System.out.print("Create Product Field Element : ");
		printProductFieldElement(resultElement);
		System.out.println();
		
		ProductFieldElement groupProduct = null;
		try {
			groupProduct = ArithmeticConvertor.ToProductFieldElement(new ByteTree(treeString), f);
			if (!groupProduct.equals(resultElement)) {
				System.out.println("Failed : the Product Field element created is different from the result");
				return (false);
			}
			System.out.println("OK : Product Field Element created");
			
		} catch (Exception e) {
			System.out.println("Failed : to create Product Field element");
			return (false);
		}
		System.out.print("The result Product Field element: ");
		printProductFieldElement(groupProduct);
		System.out.println();
		
		// convert the Field into a byte tree
		System.out.println("Converting the Product Field element backwards:");
		try {
			ByteTree b = ArithmeticConvertor.ToByteTree(groupProduct);
			
			if (0 == b.getByteString().compareToIgnoreCase(treeString)) {
				System.out.println("OK : The created byte tree is the same as the one that created the element");
			} else {
				System.out.println("Failed : The created byte tree is the different as the one that created the element");
				System.out.println(b.getByteString());
				System.out.println(treeString);
			}
		} catch (Exception e) {
			System.out.println("Failed to create the byte tree");
			return (false);
		}
		
		return (true);
	}
	
	private static void printFieldArray(FieldElement[] elements) {
		System.out.print("[");
		for (int i = 0 ; i < elements.length; i++) {
			System.out.print(elements[i].getElement());
			if (i + 1 < elements.length) {
				System.out.print(",");
			}
		}
		System.out.print("]");
	}
	
	private static boolean testFieldArray(FieldElement[] resultElement, String treeString) {
		System.out.println("Test : Array of Field Element");
		System.out.println("-------------------------------------");
		// convert the byte tree into a Field
		System.out.print("Create Array of Field Element : ");
		printFieldArray(resultElement);
		System.out.println();
		
		FieldElement[] elements = null;
		try {
			elements = ArithmeticConvertor.ToFieldElementArray(new ByteTree(treeString), f);
			if (elements.length != resultElement.length) {
				System.out.println("Failed : the Field element array created is different from the result by their sizes");
				return (false);
			}
			for (int i = 0; i < elements.length; i++) {
				if (!elements[i].equals(resultElement[i])) {
					System.out.println("Failed : the Field element no." + i + " created is different from the result");
					return (false);
				}				
			}
			
			System.out.println("OK : Array of Field Elements created");
			
		} catch (Exception e) {
			System.out.println("Failed : to create Array of Field Elements");
			return (false);
		}
		System.out.print("The result Array of Field Elements: ");
		printFieldArray(elements);
		System.out.println();
		
		// convert the Field into a byte tree
		System.out.println("Converting the Array of Field Elements backwards:");
		try {
			ByteTree b = ArithmeticConvertor.ToByteTree(elements);
			
			if (0 == b.getByteString().compareToIgnoreCase(treeString)) {
				System.out.println("OK : The created byte tree is the same as the one that created the element");
			} else {
				System.out.println("Failed : The created byte tree is the different as the one that created the element");
				System.out.println(b.getByteString());
				System.out.println(treeString);
			}
		} catch (Exception e) {
			System.out.println("Failed to create the byte tree");
			return (false);
		}
		
		return (true);
	}
	
	private static void printFieldProductArray(ProductFieldElement[] elements) {
		System.out.print("[");
		for (int i = 0 ; i < elements.length; i++) {
			printProductFieldElement(elements[i]);
			if (i + 1 < elements.length) {
				System.out.print(",");
			}
		}
		System.out.print("]");
	}
	
	private static boolean testFieldProductArray(ProductFieldElement[] resultElement, String treeString) {
		System.out.println("Test : Array of Product Field Element");
		System.out.println("-------------------------------------");
		// convert the byte tree into a Field
		System.out.print("Create Array of Product Field Element : ");
		printFieldProductArray(resultElement);
		System.out.println();
		
		ProductFieldElement[] elements = null;
		try {
			elements = ArithmeticConvertor.ToProductFieldElementArray(new ByteTree(treeString), f);
			if (elements.length != resultElement.length) {
				System.out.println("Failed : the Product Field element array created is different from the result by their sizes");
				return (false);
			}
			for (int i = 0; i < elements.length; i++) {
				if (!elements[i].equals(resultElement[i])) {
					System.out.println("Failed : the Product Field element no." + i + " created is different from the result");
					return (false);
				}				
			}
			
			System.out.println("OK : Array of Product Field Elements created");
		} catch (Exception e) {
			System.out.println("Failed : to create Product of Field Elements");
			return (false);
		}
		System.out.print("The result Array of Product Field Elements: ");
		printFieldProductArray(elements);
		System.out.println();
		
		// convert the Field into a byte tree
		System.out.println("Converting the Array of Product Field Elements backwards:");
		try {
			ByteTree b = ArithmeticConvertor.ToByteTree(elements);
			
			if (0 == b.getByteString().compareToIgnoreCase(treeString)) {
				System.out.println("OK : The created byte tree is the same as the one that created the element");
			} else {
				System.out.println("Failed : The created byte tree is the different as the one that created the element");
				System.out.println(b.getByteString());
				System.out.println(treeString);
			}
		} catch (Exception e) {
			System.out.println("Failed to create the byte tree");
			return (false);
		}
		
		return (true);
	}
}
